﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;

namespace Xceed.Silverlight.Data
{
  internal sealed class BufferInfo
  {
    #region Constructors

    internal BufferInfo()
    {
      this.Reset();
    }

    #endregion

    #region Size Property

    public int Size
    {
      get
      {
        return m_size;
      }
    }

    private int m_size; //0

    #endregion

    #region Capacity Property

    public int Capacity
    {
      get
      {
        return m_capacity;
      }
    }

    private int m_capacity; //0

    #endregion

    #region RequestsHistory Property

    public ICollection<BufferRequestInfo> RequestsHistory
    {
      get
      {
        if( m_readOnlyRequestsHistory == null )
        {
          if( m_requestsHistoryContent == null )
          {
            m_requestsHistoryContent = ( new List<BufferRequestInfo>( 0 ) ).AsReadOnly();
          }

          if( m_requestsHistoryContent.IsReadOnly )
          {
            m_readOnlyRequestsHistory = m_requestsHistoryContent;
          }
          else
          {
            m_readOnlyRequestsHistory = new ReadOnlyCollectionWrapper<BufferRequestInfo>( m_requestsHistoryContent );
          }
        }

        return m_readOnlyRequestsHistory;
      }
    }

    private ICollection<BufferRequestInfo> m_readOnlyRequestsHistory; //null
    private ICollection<BufferRequestInfo> m_requestsHistoryContent; //null

    #endregion

    #region CenterOfGravity Property

    public double CenterOfGravity
    {
      get
      {
        return m_centerOfGravity;
      }
    }

    private double m_centerOfGravity;

    #endregion

    #region CenterOfGravityThreshold Property

    public double CenterOfGravityThreshold
    {
      get
      {
        return m_centerOfGravityThreshold;
      }
    }

    private double m_centerOfGravityThreshold;

    #endregion

    #region CapacityRange Property

    public int[] CapacityRange
    {
      get
      {
        return ( int[] )m_capacityRange.Clone();
      }
    }

    private int[] m_capacityRange = new int[ 2 ];

    #endregion

    #region ActivePreFetchingSizeRange Property

    public int[] ActivePreFetchingSizeRange
    {
      get
      {
        return ( int[] )m_activePreFetchingSizeRange.Clone();
      }
    }

    private int[] m_activePreFetchingSizeRange = new int[ 2 ];

    #endregion

    #region PassivePreFetchingSizeRange Property

    public int[] PassivePreFetchingSizeRange
    {
      get
      {
        return ( int[] )m_passivePreFetchingSizeRange.Clone();
      }
    }

    private int[] m_passivePreFetchingSizeRange = new int[ 2 ];

    #endregion

    #region State Property

    public object State
    {
      get;
      set;
    }

    #endregion

    #region BufferConfiguration Internal Property

    internal BufferConfiguration BufferConfiguration
    {
      get;
      set;
    }

    #endregion

    #region RequestsHistoryLength Internal Property

    internal int RequestsHistoryLength
    {
      get
      {
        return m_requestsHistoryLength;
      }
    }

    private int m_requestsHistoryLength; //0

    #endregion

    #region IsInitialized Internal Property

    internal bool IsInitialized
    {
      get;
      set;
    }

    #endregion

    public void SetCenterOfGravity( double value )
    {
      if( ( value < 0d ) || ( value > 1d ) )
        throw new ArgumentOutOfRangeException( "value", "value must be greater than or equal to zero and less than or equal to one." );

      m_centerOfGravity = value;
    }

    public void SetCenterOfGravityThreshold( double value )
    {
      if( ( value < 0d ) || ( value > 1d ) )
        throw new ArgumentOutOfRangeException( "value", "value must be greater than or equal to zero and less than or equal to one." );

      m_centerOfGravityThreshold = value;
    }

    public void SetCapacityRange( int[] values )
    {
      this.SetRange( m_capacityRange, values );
    }

    public void SetCapacityRange( int minimum, int maximum )
    {
      this.SetRange( m_capacityRange, minimum, maximum );
    }

    public void SetActivePreFetchingSizeRange( int[] values )
    {
      this.SetRange( m_activePreFetchingSizeRange, values );
    }

    public void SetActivePreFetchingSizeRange( int minimum, int maximum )
    {
      this.SetRange( m_activePreFetchingSizeRange, minimum, maximum );
    }

    public void SetPassivePreFetchingSizeRange( int[] values )
    {
      this.SetRange( m_passivePreFetchingSizeRange, values );
    }

    public void SetPassivePreFetchingSizeRange( int minimum, int maximum )
    {
      this.SetRange( m_passivePreFetchingSizeRange, minimum, maximum );
    }

    public void SetRequestsHistoryLength( int value )
    {
      if( value < 0 )
        throw new ArgumentOutOfRangeException( "value", "value must be greater than or equal to zero." );

      m_requestsHistoryLength = value;
    }

    internal void Update(
      int size,
      int capacity,
      ICollection<BufferRequestInfo> requestsHistory )
    {
      Debug.Assert( ( size >= 0 ) && ( capacity >= 0 ) && ( requestsHistory != null ) );

      m_size = size;
      m_capacity = capacity;

      if( requestsHistory != m_requestsHistoryContent )
      {
        m_requestsHistoryContent = requestsHistory;
        m_readOnlyRequestsHistory = null;
      }
    }

    internal void Reset()
    {
      this.CleanUp();

      m_capacity = 0;
      m_centerOfGravity = 0.5d;
      m_centerOfGravityThreshold = 0.05d;
      m_requestsHistoryLength = 0;
      m_size = 0;

      this.SetCapacityRange( 0, int.MaxValue );
      this.SetActivePreFetchingSizeRange( 0, int.MaxValue );
      this.SetPassivePreFetchingSizeRange( 0, int.MaxValue );
    }

    internal void CleanUp()
    {
      m_readOnlyRequestsHistory = null;
      m_requestsHistoryContent = null;

      this.BufferConfiguration = null;
      this.IsInitialized = false;
      this.State = null;
    }

    private void SetRange( int[] range, int[] values )
    {
      if( values == null )
        throw new ArgumentNullException( "values" );

      if( values.Length != 2 )
        throw new ArgumentException( "The specified range must contain a minimum and maximum value.", "values" );

      this.SetRange( range, values[ 0 ], values[ 1 ] );
    }

    private void SetRange( int[] range, int minimum, int maximum )
    {
      if( minimum < 0 )
        throw new ArgumentException( "The value must be greater than or equal to zero.", "minimum" );

      if( maximum < 0 )
        throw new ArgumentException( "The value must be greater than or equal to zero.", "maximum" );

      if( minimum > maximum )
        throw new ArgumentOutOfRangeException( "minimum", "minimum must be less than or equal to maximum." );

      Debug.Assert( ( range != null ) && ( range.Length == 2 ) );

      range[ 0 ] = minimum;
      range[ 1 ] = maximum;
    }

    #region Private ReadOnlyCollection Nested Type

    [DebuggerDisplay( "Count = {Count}" )]
    private class ReadOnlyCollectionWrapper<T> : ICollection<T>
    {
      internal ReadOnlyCollectionWrapper( ICollection<T> collection )
      {
        if( collection == null )
          throw new ArgumentNullException( "collection" );

        m_collection = collection;
      }

      public int Count
      {
        get
        {
          return m_collection.Count;
        }
      }

      bool ICollection<T>.IsReadOnly
      {
        get
        {
          return true;
        }
      }

      void ICollection<T>.Add( T item )
      {
        throw new NotSupportedException();
      }

      void ICollection<T>.Clear()
      {
        throw new NotSupportedException();
      }

      public bool Contains( T item )
      {
        return m_collection.Contains( item );
      }

      public void CopyTo( T[] array, int arrayIndex )
      {
        m_collection.CopyTo( array, arrayIndex );
      }

      bool ICollection<T>.Remove( T item )
      {
        throw new NotSupportedException();
      }

      public IEnumerator<T> GetEnumerator()
      {
        return m_collection.GetEnumerator();
      }

      IEnumerator IEnumerable.GetEnumerator()
      {
        return this.GetEnumerator();
      }

      private ICollection<T> m_collection;
    }

    #endregion
  }
}
